package net.avcompris.binding.sax.impl;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.avcompris.common.annotation.Nullable;
import com.google.common.collect.Iterables;

final class ElementUnmarshall {

	private final Class<?> clazz;

	public ElementUnmarshall(final Class<?> clazz) {

		this.clazz = nonNullArgument(clazz, "clazz");
	}

	private final Map<String, Method> attributeMethods = new HashMap<String, Method>();

	public void addAttributeMethod(final String name, final Method method) {

		nonNullArgument(name, "name");
		nonNullArgument(method, "method");

		attributeMethods.put(name, method);
	}

	public Method getAttributeMethod(final String name) {

		nonNullArgument(name, "name");

		return attributeMethods.get(name);
	}

	private final Map<String, Method> charactersMethods = new HashMap<String, Method>();

	public void addCharactersMethod(final String path, final Method method) {

		nonNullArgument(path, "path");
		nonNullArgument(method, "method");

		charactersMethods.put(path, method);
	}

	public Method getCharactersMethod(final String path) {

		nonNullArgument(path, "path");

		return charactersMethods.get(path);
	}

	private final Map<String, Method> childMethods = new HashMap<String, Method>();

	public void addChildMethod(final String path, final Method method) {

		nonNullArgument(path, "path");
		nonNullArgument(method, "method");

		childMethods.put(path, method);
	}

	public Method getChildMethod(final String path) {

		nonNullArgument(path, "path");

		return childMethods.get(path);
	}

	public Class<?> getClassToInstantiate() {

		return clazz;
	}

	public Iterable<Method> getAllMethods() {

		return Iterables.concat(charactersMethods.values(), childMethods
				.values());
	}

	@Override
	public String toString() {

		return "[" + getClass().getName() + ":" + clazz.getName() + "]";
	}

	@Override
	public boolean equals(@Nullable final Object o) {

		if (o == null) {
			return false;
		}

		if (!ElementUnmarshall.class.equals(o.getClass())) {
			return false;
		}

		return clazz.equals(((ElementUnmarshall) o).clazz);
	}

	@Override
	public int hashCode() {

		return clazz.hashCode();
	}
}
